// Copyright 2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Features examples.
// Author: Kai Huang

{namespace soy.examples.features}


/**
 * Demo comments.
 */
{template .demoComments}
  blah blah<br>  // comment comment
  /* comment
     comment */
  // Note: The '//' below doesn't start a comment because it's preceded by a non-whitespace.
  http://www.google.com<br>
{/template}


/**
 * Demo line joining.
 */
{template .demoLineJoining}

  // Without any HTML or Soy tags at the end of the first line or start of the second line, the two
  // lines will be joined by adding a space.
  First
  second.<br>

  // With either an HTML or Soy tag bordering the join location (end of the first line or start of
  // the second line), the lines will be joined without adding a space.
  // Example with HTML tag at end of first line:
  <i>First</i>
  second.<br>
  // Example with Soy tag at start of second line:
  First
  {''}second.<br>

  // To add a space to a line-joining location where a space would not normally be added (because
  // (it borders an HTML or Soy tag), use the {sp} tag.
  <i>First</i>{sp}
  second.<br>

  // To prevent a space from being added to a line-joining location where a space would normally be
  // added, use the {nil} tag. This tag prints nothing (empty string), but causes the line-joining
  // location to border a Soy tag, thus preventing the line-joining space.
  First{nil}
  second.<br>

{/template}


/**
 * Demo raw text commands.
 */
{template .demoRawTextCommands}
  <pre>
  // Special characters.
  Space       : AA{sp}BB<br>
  Empty string: AA{nil}BB<br>
  New line    : AA{\n}BB<br>
  Carriage ret: AA{\r}BB<br>
  Tab         : AA{\t}BB<br>
  Left brace  : AA{lb}BB<br>
  Right brace : AA{rb}BB<br>

  // Literal block.
  // Note: Lines are not joined and indentation is not stripped, so the new line and 2-space indent
  // between 'CC' and 'DD' will appear in the output exactly as written.
  Literal     : {literal}AA	BB { CC
  DD } EE {sp}{\n}{rb} FF{/literal}
  </pre>
{/template}


/**
 * Demo 'print'.
 * @param boo Something scary.
 * @param two Preferably the number 2.
 */
{template .demoPrint}
  {print 'Boo!'}<br>  // print a string
  {'Boo!'}<br>  // the command name 'print' is implied
  {1 + 2}<br>  // print the result of an expression
  {$boo}<br>  // print a data value
  {1 + $two}<br>  // print the result of an expression that uses a data value
  {GLOBAL_INT}, {GLOBAL_BOOL}.<br>  // print globals
{/template}


/**
 * Demo print directives.
 * @param longVarName Some ridiculously long variable name.
 * @param elementId The id for an element.
 * @param cssClass A CSS class name.
 */
{template .demoPrintDirectives}
  insertWordBreaks:<br>
  <div style="width:150px; border:1px solid #00CC00">
    {$longVarName}<br>  // will run outside the div border
    {$longVarName |insertWordBreaks:5}<br>  // will be allowed to wrap
  </div>

  id:<br>
  // The 'id' and 'class' attributes of this span will not be needlessly autoescaped because they
  // are marked with the print directive '|id'.
  // Note: Only use '|id' with identifiers like id and class (otherwise use '|noAutoescape').
  <span id="{$elementId|id}" class="{$cssClass|id}" style="border:1px solid #000000">
    Hello
  </span>
{/template}


/**
 * Demo autoescape true.
 * @param italicHtml A string surrounded by HTML italics tags.
 */
{template .demoAutoescapeTrue autoescape="true"}
  // Note: We explicitly list autoescape="true" in the 'template' tag for demonstration. Usually
  // it's omitted because "true" is the attribute's default value.
  // Note: The parameter name 'italicHtml' demonstrates the good practice of adding the suffix
  // 'Html' to identify strings that may contain HTML tags and are known to be safe.

  {$italicHtml}<br>  // autoescape causes HTML tags to appear literally
  {$italicHtml |noAutoescape}<br>  // noAutoescape directive prevents autoescaping
{/template}


/**
 * Demo autoescape false.
 * @param italicHtml A string surrounded by HTML italics tags.
 */
{template .demoAutoescapeFalse autoescape="false"}
  // Note: Use autoescape="false" with care, as more cross-site scripting bugs may slip through.

  {$italicHtml}<br>  // no autoescaping will be applied
  {$italicHtml |escapeHtml}<br>  // escapeHtml directive applies HTML escaping
{/template}


/**
 * Demo 'msg'.
 * @param name The name of the person to say hello to.
 * @param labsUrl The URL of the unreleased 'Labs' feature.
 */
{template .demoMsg}

  {msg desc="Says hello to a person."}
    Hello {$name}!
  {/msg}<br>

  {msg desc="Link to the unreleased 'Labs' feature."}
    Click <a href="{$labsUrl}">here</a> to access Labs.
  {/msg}<br>

  // The 'meaning' attribute is used when you have two messages that are exactly the same string in
  // English, but may be translated to different strings in other languages. The 'meaning' attribute
  // should then be a short string that distinguishes the two strings, and will be used for
  // generating different message ids. The 'meaning' will not be shown to translators, so you must
  // still communicate all the details in the 'desc' text.
  {msg meaning="noun" desc="The word 'Archive' used as a noun, i.e. an information store."}
    Archive
  {/msg}<br>
  {msg meaning="verb" desc="The word 'Archive' used as a verb, i.e. to store information."}
    Archive
  {/msg}<br>

{/template}


/**
 * Demo 'if'.
 * @param pi An approximate value for pi.
 */
{template .demoIf}
  {if round($pi, 2) == 3.14}
    {msg desc="Example: 3.1416 is a good approximation of pi."}
      {$pi} is a good approximation of pi.
    {/msg}
  {elseif round($pi) == 3}
    {msg desc="Example: 3.1 is a bad approximation of pi."}
      {$pi} is a bad approximation of pi.
    {/msg}
  {else}
    {msg desc="Example: 5 is nowhere near the value of pi."}
      {$pi} is nowhere near the value of pi.
    {/msg}
  {/if}
  <br>
{/template}


/**
 * Demo 'switch'.
 * @param name The name of a kid.
 */
{template .demoSwitch}
  Dear {$name}, &nbsp;

  {switch $name}
    {case 'Go'}
      You've been bad this year.
    {case 'Fay', 'Ivy'}
      You've been good this year.
    {default}
      You don't really believe in me, do you?
  {/switch}

  &nbsp; --Santa<br>
{/template}


/**
 * Demo 'foreach'.
 * @param persons List of persons. Each person must have 'name' and 'numWaffles'.
 */
{template .demoForeach}

  {foreach $person in $persons}

    {if isFirst($person)}
      First,
    {elseif isLast($person)}
      Finally,
    {else}
      Then
    {/if}
    {sp}

    {if $person.numWaffles == 1}
      {$person.name} ate 1 waffle.
    {else}
      {$person.name} ate {$person.numWaffles} waffles.
    {/if}
    <br>

  {ifempty}
    Nobody here ate any waffles.<br>

  {/foreach}

{/template}


/**
 * Demo 'for'.
 * @param numLines The number of lines to display.
 */
{template .demoFor}

  {for $i in range($numLines)}
    Line {$i + 1} of {$numLines}.<br>
  {/for}

  {for $i in range(2, 10, 2)}
    {$i}...{sp}
  {/for}
  Who do we appreciate?<br>

{/template}


/**
 * Demo 'call' without 'param's.
 * @param name The name of the person who took a trip.
 * @param tripInfo The full record of the trip ('name' and 'destination').
 */
{template .demoCallWithoutParam}

  // Call template defined in a different file.
  {call soy.examples.simple.helloWorld /}<br>

  // Call template defined in this file.
  {call .tripReport_ /}<br>

  // Pass all of the current template data to the callee.
  // Note: Only the top-level key 'name' will be used because it matches the name of a parameter
  // expected by the callee.
  {call .tripReport_ data="all" /}<br>

  // Pass a subset of the current template data to the callee.
  {call .tripReport_ data="$tripInfo" /}<br>

{/template}


/**
 * Demo 'call' with 'param's.
 * @param name The name of the person who took the trips.
 * @param companionName The name of the person who went along for the odd-numbered trips only.
 * @param destinations List of destinations visited by this person.
 */
{template .demoCallWithParam}

  {foreach $destination in $destinations}

    // Pass the current template data and also pass a parameter.
    // Note: Only passing data="all" is not sufficient for providing the 'destination' parameter of
    // the callee because $destination is a local variable here, not part of the template data
    // passed by data="all".
    {call .tripReport_ data="all"}
      {param destination: $destination /}
    {/call}<br>

    {if index($destination) % 2 == 0}  // even index means odd-numbered trip since index is 0-based
      // Pass two parameters.
      {call .tripReport_}
        {param name: $companionName /}
        {param destination: $destination /}
      {/call}<br>
    {/if}

  {/foreach}

{/template}


/**
 * Demo 'call' with a 'param' block.
 * @param name The name of the person who took the trip.
 */
{template .demoCallWithParamBlock}
  // Pass 2 parameters, one of which is built using Soy code.
  {call .tripReport_}
    {param name: $name /}
    {param destination}
      {switch randomInt(3)}
        {case 0}Boston
        {case 1}Singapore
        {case 2}Zurich
      {/switch}
    {/param}
  {/call}
  <br>
{/template}


/**
 * Private helper for demoCallWithoutParams, demoCallWithParams, and demoCallWithParamBlock.
 * Reports on a trip.
 * @param? name The name of the person who took a trip (optional).
 * @param? destination The destination of the trip (optional).
 */
{template .tripReport_ private="true"}
  // Note: The template name demonstrates the good practice of adding a trailing underscore to
  // private templates (template that should never be called from hand-written code).

  // Note: All parameters to this template are optional. Therefore, below, we must check for
  // "not (hasData() and $name)" rather than simply "not $name" because if absolutely no data is
  // passed, then evaluating "$name" will cause an exception.
  {if not (hasData() and $name)}
    // Note: The message below demonstrates that the 'desc' attribute can be left empty. However,
    // this is not recommended except for the simplest messages, otherwise you risk confusing some
    // translators and getting poor translations.
    {msg desc=""}
      A trip was taken.
    {/msg}
  {elseif not $destination}
    {msg desc="Example: Alice took a trip."}
      {$name} took a trip.
    {/msg}
  {else}
    {msg desc="Example: Alice took a trip to wonderland."}
      {$name} took a trip to {$destination}.
    {/msg}
  {/if}
{/template}


/**
 * Demo {param} blocks with 'kind' attribute.
 * @param message A message text.
 * @param list A list of things.
 */
{template .demoParamWithKindAttribute autoescape="contextual"}
  <div>
    {call .demoParamWithKindAttributeCallee_}
      // Note that the {param} blocks for the message and listItems parameter are declared to have
      // content of kind HTML. This instructs the contextual autoescaper to process the content of
      // these blocks as HTML, and to wrap the the value of the parameter as a soydata.SanitizedHtml
      // object.
      {param message kind="html"}
        <b>{$message}</b>
      {/param}
      {param listItems kind="html"}
        {foreach $i in $list}
          <li>{$i}</li>
        {/foreach}
      {/param}
    {/call}
  </div>
{/template}


/**
 * Demo {param} blocks with 'kind' attribute.
 * @param message A message with HTML markup.
 * @param listItems A HTML-formatted list.
 */
{template .demoParamWithKindAttributeCallee_ private="true" autoescape="contextual"}
  // Note that both $message and $listItems contain HTML markup produced by a {param} block in the
  // the calling template.  Since the {param} blocks are declared to have HTML content, their values
  // are wrapped as soydata.SanitizedHtml objects.  This in turn causes them to be emitted here
  // without further escaping.  In particular, it is not necessary to use the |noAutoescape print
  // directive to prevent double-escaping.
  <div>{$message}</div>
  <ol>
    {$listItems}
  </ol>
{/template}


/**
 * Demo expressions.
 * @param students Nonempty list of students. Each student must have 'name', 'major', and 'year'.
 * @param currentYear The current year.
 */
{template .demoExpressions}

  First student's major: {$students.0.major}<br>
  Last student's year: {$students[length($students) - 1].year}<br>
  Random student's major: {$students[randomInt(length($students))].major}<br>

  {foreach $student in $students}
    {$student.name}:

    {if isFirst($student)}
      {sp}First.
    {elseif isLast($student)}
      {sp}Last.
    // Note: must use floor() in next check since division is floating-point.
    {elseif index($student) == ceiling(length($students) / 2) - 1}
      {sp}Middle.
    {/if}

    {if index($student) % 2 == 1} Even.{/if}
    {sp}{$student.major}.
    {if $student.major == 'Physics' or $student.major == 'Biology'} Scientist.{/if}
    {if $currentYear - $student.year < 10} Young.{/if}

    // The following print statement prints "70s", "80s", "90s", or "00s". Note that "00s" is a
    // special case since using the same expression would yield "0s", not "00s".
    {sp}{$student.year < 2000 ? round($student.year - 1905, -1) + 's' : '00s'}.
    // Equivalent to previous line.
    {sp}{if $student.year < 2000}{round($student.year - 1905, -1)}{else}00{/if}s.

    <br>
  {/foreach}

{/template}


/**
 * Demo double braces.
 * @param setName The name of the infinite set.
 * @param setMembers List of the first few members of the set.
 */
{template .demoDoubleBraces}
  // If a Soy tag needs to have brace characters within, use double braces to delimit the tag.
  {{msg desc="Example: The set of prime numbers is {2, 3, 5, 7, 11, 13, ...}."}}
    // Note: This message also demonstrates a useful trick. Since a 'msg' block cannot contain a
    // 'foreach' statement (impossible to translate as one message), we use a 'call' to a helper
    // template that contains the 'foreach' loop. In order to use this trick, please observe the
    // following: (a) the output of the 'call' must not contain translated content, otherwise the
    // message would be translated in multiple parts and may not read correctly in some languages,
    // (b) since the whole 'call' turns into a single placeholder, be sure to provide a clear
    // description and example to the translator.
    The set of {$setName} is {lb}
    {call .buildCommaSeparatedList_}
      {param items: $setMembers /}
    {/call}
    , ...{rb}.
  {/msg}
{/template}


/**
 * Private helper to build a comma separated list.
 * @param items The list of items.
 */
{template .buildCommaSeparatedList_ private="true"}
  {foreach $item in $items}
    {if not isFirst($item)}
      ,{sp}
    {/if}
    {$item}
  {/foreach}
{/template}


/**
 * Demo BiDi support.
 * @param title Book title.
 * @param author Author's name.
 * @param year Year published.
 * @param keywords List of keywords.
 */
{template .demoBidiSupport}

  // If $title has the opposite directionality relative to the overall locale, it needs to be
  // declared as such using the dir attribute on the element around it. Otherwise, it may be
  // garbled. For example, in an RTL page, an LTR value like "101 Dalmatians!" will be displayed
  // as "!Dalmatians 101".
  //
  // Setting the dir attribute on a block element like <div> has the side-effect of setting its
  // default alignment. In some cases, this is desirable, since text is generally more readable
  // when start-aligned. In such cases, we declare directionality using the bidiDirAttr() function,
  // which returns dir="ltr" for an LTR value in an RTL locale, dir="rtl" for an RTL value in an LTR
  // locale, and an empty string otherwise.
  //
  <div id="title1" style="font-variant:small-caps" {bidiDirAttr($title)}>
    {$title}
  </div>

  // In other cases, changing alignment may do more harm than good by upsetting the layout of the
  // page, and we do not want to do it. Our $title seems to be one such case. To avoid setting the
  // dir attribute on the <div>, we declare $title's directionality using the |bidiSpanWrap print
  // directive, which wraps the value to be printed in a <span dir="ltr">, <span dir="rtl">, or
  // nothing at all when it has the same directionality as the locale.
  <div id="title2" style="font-variant:small-caps">
    {$title |bidiSpanWrap}
  </div>

  // The |bidiSpanWrap directive is in fact the usual way to declare directionality. One of its
  // advantages is that it can be used when the possibly opposite-directionality value, like our
  // $author here, is not already wrapped in an element of its own, without adding to the size of
  // the output in the usual case of same directionality.
  //
  // Another even more important advantage is that it prevents an opposite-directionality value
  // from "sticking" to a number or another opposite-directionality string following it in-line. In
  // this case, for example, it makes sure we get 'by HEBREW NAME (2009)', not
  // 'by 2009) HEBREW NAME)'.
  {msg desc="Indicates who wrote the book and when, e.g. 'by Rudyard Kipling (1892)'"}
    by {$author |bidiSpanWrap} ({$year})
  {/msg}

  <div id="choose_a_keyword">
    // Please note that messages, by definition being in the language of the overall locale, can
    // not be of the opposite directionality and do not need directionality declaration.
    {msg desc="Ask user to pick best keyword"}Your favorite keyword{/msg}:{sp}
    <select>
      {foreach $keyword in $keywords}
        // Mark-up is not allowed under the option element, and setting its dir attribute does not
        // do what one would expect. The only way to prevent the garbling of opposite-
        // directionality options is to use |bidiUnicodeWrap, which wraps its input in Unicode BiDi
        // formatting characters that declare its directionality. So why not always use
        // |bidiUnicodeWrap instead of |bidiSpanWrap? Because the W3C strongly deprecates the use
        // of the formatting characters it uses except in places where mark-up cannot be used.
        <option value="{$keyword}">{$keyword |bidiUnicodeWrap}</option>
      {/foreach}
    </select>
  </div>

  // Since most of the layout of an RTL page is supposed to be the mirror image of an LTR page,
  // most instances of 'left' and 'right' in the style should be replaced with {bidiStartEdge()}
  // and {bidiEndEdge()}, respectively. Here, we want the Help link at the "far" edge of the page,
  // i.e. on the right in LTR and on the left in RTL.
  <a href="#" style="float:{bidiEndEdge()}">{msg desc="Link to Help"}Help{/msg}</a>
  <br>

{/template}


/**
 * Template that outputs -1 in a right-to-left page and 1 in a left-to-right page, i.e. basically
 * exposes the results of Soy's bidiGlobalDir() to scripts.
 */
{template .bidiGlobalDir}
  {bidiGlobalDir()}
{/template}


/**
 * Template for printing the header to add before each example.
 * @param exampleNum The number of the example.
 * @param exampleName The name of the example.
 */
{template .exampleHeader}
  <hr>
  <b>{$exampleNum}. {$exampleName}</b><br>
{/template}
